{
  "nbformat": 4,
  "nbformat_minor": 0,
  "metadata": {
    "colab": {
      "provenance": []
    },
    "kernelspec": {
      "name": "python3",
      "display_name": "Python 3"
    },
    "language_info": {
      "name": "python"
    }
  },
  "cells": [
    {
      "cell_type": "code",
      "source": [
        "!pip -q install crewai langchain-groq duckduckgo-search"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "0FDPgaevdeNQ",
        "outputId": "d93b98b1-5d9c-42c8-a726-81004ded4d18"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m61.6/61.6 kB\u001b[0m \u001b[31m801.8 kB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m192.7/192.7 kB\u001b[0m \u001b[31m3.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m817.7/817.7 kB\u001b[0m \u001b[31m12.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m311.2/311.2 kB\u001b[0m \u001b[31m16.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m60.1/60.1 kB\u001b[0m \u001b[31m4.0 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m106.1/106.1 kB\u001b[0m \u001b[31m5.9 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m291.3/291.3 kB\u001b[0m \u001b[31m14.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m1.8/1.8 MB\u001b[0m \u001b[31m28.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m75.0/75.0 kB\u001b[0m \u001b[31m4.0 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m5.5/5.5 MB\u001b[0m \u001b[31m28.6 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m141.1/141.1 kB\u001b[0m \u001b[31m867.2 kB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m233.4/233.4 kB\u001b[0m \u001b[31m12.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m525.5/525.5 kB\u001b[0m \u001b[31m28.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m131.5/131.5 kB\u001b[0m \u001b[31m11.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m41.3/41.3 kB\u001b[0m \u001b[31m3.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m278.2/278.2 kB\u001b[0m \u001b[31m17.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m71.1/71.1 kB\u001b[0m \u001b[31m4.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m2.0/2.0 MB\u001b[0m \u001b[31m63.6 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m75.6/75.6 kB\u001b[0m \u001b[31m6.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m1.9/1.9 MB\u001b[0m \u001b[31m62.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m115.2/115.2 kB\u001b[0m \u001b[31m5.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m53.0/53.0 kB\u001b[0m \u001b[31m3.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m50.8/50.8 kB\u001b[0m \u001b[31m3.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m78.8/78.8 kB\u001b[0m \u001b[31m5.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m2.4/2.4 MB\u001b[0m \u001b[31m35.9 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m91.9/91.9 kB\u001b[0m \u001b[31m5.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m60.8/60.8 kB\u001b[0m \u001b[31m4.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m5.4/5.4 MB\u001b[0m \u001b[31m43.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m6.8/6.8 MB\u001b[0m \u001b[31m43.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m67.3/67.3 kB\u001b[0m \u001b[31m5.9 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[?25h  Installing build dependencies ... \u001b[?25l\u001b[?25hdone\n",
            "  Getting requirements to build wheel ... \u001b[?25l\u001b[?25hdone\n",
            "  Preparing metadata (pyproject.toml) ... \u001b[?25l\u001b[?25hdone\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m698.9/698.9 kB\u001b[0m \u001b[31m34.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m1.6/1.6 MB\u001b[0m \u001b[31m41.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m67.6/67.6 kB\u001b[0m \u001b[31m5.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m49.4/49.4 kB\u001b[0m \u001b[31m4.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m77.9/77.9 kB\u001b[0m \u001b[31m6.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m58.3/58.3 kB\u001b[0m \u001b[31m4.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m71.9/71.9 kB\u001b[0m \u001b[31m8.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m46.0/46.0 kB\u001b[0m \u001b[31m4.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m341.4/341.4 kB\u001b[0m \u001b[31m25.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m3.4/3.4 MB\u001b[0m \u001b[31m52.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m1.3/1.3 MB\u001b[0m \u001b[31m65.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m130.2/130.2 kB\u001b[0m \u001b[31m13.9 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m86.8/86.8 kB\u001b[0m \u001b[31m8.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[?25h  Building wheel for pypika (pyproject.toml) ... \u001b[?25l\u001b[?25hdone\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "!pip show crewai"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "cEIeTK_9uFvL",
        "outputId": "622e41be-26d7-4a88-8280-752e00ddc8f4"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Name: crewai\n",
            "Version: 0.28.8\n",
            "Summary: Cutting-edge framework for orchestrating role-playing, autonomous AI agents. By fostering collaborative intelligence, CrewAI empowers agents to work together seamlessly, tackling complex tasks.\n",
            "Home-page: \n",
            "Author: Joao Moura\n",
            "Author-email: joao@crewai.com\n",
            "License: \n",
            "Location: /usr/local/lib/python3.10/dist-packages\n",
            "Requires: appdirs, click, embedchain, instructor, langchain, openai, opentelemetry-api, opentelemetry-exporter-otlp-proto-http, opentelemetry-sdk, pydantic, python-dotenv, regex\n",
            "Required-by: \n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "# The goal\n",
        "\n",
        "Reply to a customer email\n",
        "1. get the email\n",
        "2. categorize this as a \"sales\", \"custom enquiry\", \"off topic\", \"customer complaint\"\n",
        "3. use the category to research info needed for the reply\n",
        "4. take the info and check if there is enough to answer the email\n",
        "5. write a reply\n",
        "6. check the reply\n",
        "7. save the email\n",
        "\n",
        "### Agents\n",
        "- categorizer\n",
        "- researcher (web for now would be internal RAG)\n",
        "- email writer\n",
        "\n",
        "\n",
        "### Tasks\n",
        "- categorize email\n",
        "- research the answer\n",
        "- write the email"
      ],
      "metadata": {
        "id": "tYH3vJxvjVve"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "import os\n",
        "from google.colab import userdata\n",
        "\n",
        "os.environ[\"GROQ_API_KEY\"] = userdata.get('GROQ_API_KEY')"
      ],
      "metadata": {
        "id": "oMAPjXCXcd8a"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "source": [
        "## Utilities"
      ],
      "metadata": {
        "id": "b9kHdE8Na8i4"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "import json  # Import the JSON module to parse JSON strings\n",
        "from langchain_core.agents import AgentFinish\n",
        "\n",
        "agent_finishes  = []\n",
        "\n",
        "import json\n",
        "from typing import Union, List, Tuple, Dict\n",
        "from langchain.schema import AgentFinish\n",
        "\n",
        "call_number = 0\n",
        "\n",
        "def print_agent_output(agent_output: Union[str, List[Tuple[Dict, str]], AgentFinish], agent_name: str = 'Generic call'):\n",
        "    global call_number  # Declare call_number as a global variable\n",
        "    call_number += 1\n",
        "    with open(\"crew_callback_logs.txt\", \"a\") as log_file:\n",
        "        # Try to parse the output if it is a JSON string\n",
        "        if isinstance(agent_output, str):\n",
        "            try:\n",
        "                agent_output = json.loads(agent_output)  # Attempt to parse the JSON string\n",
        "            except json.JSONDecodeError:\n",
        "                pass  # If there's an error, leave agent_output as is\n",
        "\n",
        "        # Check if the output is a list of tuples as in the first case\n",
        "        if isinstance(agent_output, list) and all(isinstance(item, tuple) for item in agent_output):\n",
        "            print(f\"-{call_number}----Dict------------------------------------------\", file=log_file)\n",
        "            for action, description in agent_output:\n",
        "                # Print attributes based on assumed structure\n",
        "                print(f\"Agent Name: {agent_name}\", file=log_file)\n",
        "                print(f\"Tool used: {getattr(action, 'tool', 'Unknown')}\", file=log_file)\n",
        "                print(f\"Tool input: {getattr(action, 'tool_input', 'Unknown')}\", file=log_file)\n",
        "                print(f\"Action log: {getattr(action, 'log', 'Unknown')}\", file=log_file)\n",
        "                print(f\"Description: {description}\", file=log_file)\n",
        "                print(\"--------------------------------------------------\", file=log_file)\n",
        "\n",
        "        # Check if the output is a dictionary as in the second case\n",
        "        elif isinstance(agent_output, AgentFinish):\n",
        "            print(f\"-{call_number}----AgentFinish---------------------------------------\", file=log_file)\n",
        "            print(f\"Agent Name: {agent_name}\", file=log_file)\n",
        "            agent_finishes.append(agent_output)\n",
        "            # Extracting 'output' and 'log' from the nested 'return_values' if they exist\n",
        "            output = agent_output.return_values\n",
        "            # log = agent_output.get('log', 'No log available')\n",
        "            print(f\"AgentFinish Output: {output['output']}\", file=log_file)\n",
        "            # print(f\"Log: {log}\", file=log_file)\n",
        "            # print(f\"AgentFinish: {agent_output}\", file=log_file)\n",
        "            print(\"--------------------------------------------------\", file=log_file)\n",
        "\n",
        "        # Handle unexpected formats\n",
        "        else:\n",
        "            # If the format is unknown, print out the input directly\n",
        "            print(f\"-{call_number}-Unknown format of agent_output:\", file=log_file)\n",
        "            print(type(agent_output), file=log_file)\n",
        "            print(agent_output, file=log_file)\n"
      ],
      "metadata": {
        "id": "DvdcABrTa-rR"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "from langchain_groq import ChatGroq\n",
        "\n",
        "GROQ_LLM = ChatGroq(\n",
        "            # api_key=os.getenv(\"GROQ_API_KEY\"),\n",
        "            model=\"llama3-70b-8192\"\n",
        "        )\n"
      ],
      "metadata": {
        "id": "uzWrf9n6adVo"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "source": [
        "## Tools"
      ],
      "metadata": {
        "id": "8G40lprgkCJ2"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "from crewai import Crew, Agent, Task, Process\n",
        "from langchain_community.tools import DuckDuckGoSearchRun"
      ],
      "metadata": {
        "id": "oYA43C0An6tn"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "from datetime import datetime\n",
        "from random import randint\n",
        "from langchain.tools import tool"
      ],
      "metadata": {
        "id": "f3GvksYIkA1m"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "import json\n",
        "import os\n",
        "\n",
        "import requests\n",
        "from langchain.tools import tool\n",
        "\n",
        "import os\n",
        "from crewai import Agent, Task, Crew, Process\n",
        "from langchain_community.tools import DuckDuckGoSearchRun\n",
        "from langchain.agents import load_tools\n",
        "\n",
        "search_tool = DuckDuckGoSearchRun()\n"
      ],
      "metadata": {
        "id": "vc8SeVoUn5Q6"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "search_tool.run(\"usb key price\")"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 174
        },
        "id": "Nvbxjcy8jJ56",
        "outputId": "901554a1-94ee-4ed9-e011-95392cc9a8bb"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "'The Feitian ePass K9 USB Security Key offers all the features expected from a security key at an affordable price. ... The USB-C key is best suited for businesses that want to implement physical ... Best security. 7. Kingston IronKey Keypad 200. View at Amazon. View at Amazon. View at Newegg. The best USB flash drive for security This ultra secure flash drive features USB 3.2 Gen 1 speeds and ... It usually costs about $20-$30 less than the faster Kingston DataTraveler Max, while still delivering 616.9 MB/s sequential read speed and 543.9 MB/s sequential writes in our CrystalDiskMark tests ... YubiKey 5 NFC USB-A. Best Premium Security Key. The YubiKey 5 provides the most comprehensive protocols of any security key out there, as well as some excellent additional features for those who are security conscious. $50 at Amazon. No USB-C connection. -. Bigger than Nano version. Manufactured by Yubico, the codeveloper of the FIDO U2F open authentication standard used by many security keys, the YubiKey 5 NFC is in a safe ...'"
            ],
            "application/vnd.google.colaboratory.intrinsic+json": {
              "type": "string"
            }
          },
          "metadata": {},
          "execution_count": 8
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "## Agents"
      ],
      "metadata": {
        "id": "1FhZyiMakLNL"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "class EmailAgents():\n",
        "    def make_categorizer_agent(self):\n",
        "        return Agent(\n",
        "            role='Email Categorizer Agent',\n",
        "            goal=\"\"\"take in a email from a human that has emailed out company email address and categorize it \\\n",
        "            into one of the following categories: \\\n",
        "            price_equiry - used when someone is asking for information about pricing \\\n",
        "            customer_complaint - used when someone is complaining about something \\\n",
        "            product_enquiry - used when someone is asking for information about a product feature, benefit or service but not about pricing \\\\\n",
        "            customer_feedback - used when someone is giving feedback about a product \\\n",
        "            off_topic when it doesnt relate to any other category \"\"\",\n",
        "            backstory=\"\"\"You are a master at understanding what a customer wants when they write an email and are able to categorize it in a useful way\"\"\",\n",
        "            llm=GROQ_LLM,\n",
        "            verbose=True,\n",
        "            allow_delegation=False,\n",
        "            max_iter=5,\n",
        "            memory=True,\n",
        "            step_callback=lambda x: print_agent_output(x,\"Email Categorizer Agent\"),\n",
        "        )\n",
        "\n",
        "    def make_researcher_agent(self):\n",
        "        return Agent(\n",
        "            role='Info Researcher Agent',\n",
        "            goal=\"\"\"take in a email from a human that has emailed out company email address and the category \\\n",
        "            that the categorizer agent gave it and decide what information you need to search for for the email writer to reply to \\\n",
        "            the email in a thoughtful and helpful way.\n",
        "            If you DONT think a search will help just reply 'NO SEARCH NEEDED'\n",
        "            If you dont find any useful info just reply 'NO USEFUL RESESARCH FOUND'\n",
        "            otherwise reply with the info you found that is useful for the email writer\n",
        "            \"\"\",\n",
        "            backstory=\"\"\"You are a master at understanding what information our email writer needs  to write a reply that \\\n",
        "            will help the customer\"\"\",\n",
        "            llm=GROQ_LLM,\n",
        "            verbose=True,\n",
        "            max_iter=5,\n",
        "            allow_delegation=False,\n",
        "            memory=True,\n",
        "            tools=[search_tool],\n",
        "            step_callback=lambda x: print_agent_output(x,\"Info Researcher Agent\"),\n",
        "        )\n",
        "\n",
        "    def make_email_writer_agent(self):\n",
        "        return Agent(\n",
        "            role='Email Writer Agent',\n",
        "            goal=\"\"\"take in a email from a human that has emailed out company email address, the category \\\n",
        "            that the categorizer agent gave it and the research from the research agent and \\\n",
        "            write a helpful email in a thoughtful and friendly way.\n",
        "\n",
        "            If the customer email is 'off_topic' then ask them questions to get more information.\n",
        "            If the customer email is 'customer_complaint' then try to assure we value them and that we are addressing their issues.\n",
        "            If the customer email is 'customer_feedback' then try to assure we value them and that we are addressing their issues.\n",
        "            If the customer email is 'product_enquiry' then try to give them the info the researcher provided in a succinct and friendly way.\n",
        "            If the customer email is 'price_equiry' then try to give the pricing info they requested.\n",
        "\n",
        "            You never make up information. that hasn't been provided by the researcher or in the email.\n",
        "            Always sign off the emails in appropriate manner and from Sarah the Resident Manager.\n",
        "            \"\"\",\n",
        "            backstory=\"\"\"You are a master at synthesizing a variety of information and writing a helpful email \\\n",
        "            that will address the customer's issues and provide them with helpful information\"\"\",\n",
        "            llm=GROQ_LLM,\n",
        "            verbose=True,\n",
        "            allow_delegation=False,\n",
        "            max_iter=5,\n",
        "            memory=True,\n",
        "            step_callback=lambda x: print_agent_output(x,\"Email Writer Agent\"),\n",
        "        )\n",
        "\n"
      ],
      "metadata": {
        "id": "Hbe-5rH_nHqf"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "source": [
        "## Tasks"
      ],
      "metadata": {
        "id": "0CxGkAovkUVK"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "class EmailTasks():\n",
        "    # Define your tasks with descriptions and expected outputs\n",
        "    def categorize_email(self, email_content):\n",
        "        return Task(\n",
        "            description=f\"\"\"Conduct a comprehensive analysis of the email provided and categorize into \\\n",
        "            one of the following categories:\n",
        "            price_equiry - used when someone is asking for information about pricing \\\n",
        "            customer_complaint - used when someone is complaining about something \\\n",
        "            product_enquiry - used when someone is asking for information about a product feature, benefit or service but not about pricing \\\\\n",
        "            customer_feedback - used when someone is giving feedback about a product \\\n",
        "            off_topic when it doesnt relate to any other category \\\n",
        "\n",
        "            EMAIL CONTENT:\\n\\n {email_content} \\n\\n\n",
        "            Output a single cetgory only\"\"\",\n",
        "            expected_output=\"\"\"A single categtory for the type of email from the types ('price_equiry', 'customer_complaint', 'product_enquiry', 'customer_feedback', 'off_topic') \\\n",
        "            eg:\n",
        "            'price_enquiry' \\\n",
        "            \"\"\",\n",
        "            output_file=f\"email_category.txt\",\n",
        "            agent=categorizer_agent\n",
        "            )\n",
        "\n",
        "    def research_info_for_email(self, email_content):\n",
        "        return Task(\n",
        "            description=f\"\"\"Conduct a comprehensive analysis of the email provided and the category \\\n",
        "            provided and search the web to find info needed to respond to the email\n",
        "\n",
        "            EMAIL CONTENT:\\n\\n {email_content} \\n\\n\n",
        "            Only provide the info needed DONT try to write the email\"\"\",\n",
        "            expected_output=\"\"\"A set of bullet points of useful info for the email writer \\\n",
        "            or clear instructions that no useful material was found.\"\"\",\n",
        "            context = [categorize_email],\n",
        "            output_file=f\"research_info.txt\",\n",
        "            agent=researcher_agent\n",
        "            )\n",
        "\n",
        "    def draft_email(self, email_content):\n",
        "        return Task(\n",
        "            description=f\"\"\"Conduct a comprehensive analysis of the email provided, the category provided\\\n",
        "            and the info provided from the research specialist to write an email. \\\n",
        "\n",
        "            Write a simple, polite and too the point email which will respond to the customer's email. \\\n",
        "            If useful use the info provided from the research specialist in the email. \\\n",
        "\n",
        "            If no useful info was provided from the research specialist the answer politely but don't make up info. \\\n",
        "\n",
        "            EMAIL CONTENT:\\n\\n {email_content} \\n\\n\n",
        "            Output a single cetgory only\"\"\",\n",
        "            expected_output=\"\"\"A well crafted email for the customer that addresses their issues and concerns\"\"\",\n",
        "            context = [categorize_email, research_info_for_email],\n",
        "            agent=email_writer_agent,\n",
        "            output_file=f\"draft_email.txt\",\n",
        "            )"
      ],
      "metadata": {
        "id": "6gYSmym8pdum"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "source": [
        "## Instantiate Agents and Tasks"
      ],
      "metadata": {
        "id": "m4xowf-0qXzf"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "# EMAIL = \"\"\"HI there, \\n\n",
        "# I am emailing to find out the current price of Bitcoin. \\n\n",
        "\n",
        "# Can you please help me/\n",
        "\n",
        "# Thanks,\n",
        "# John\n",
        "# \"\"\"\n",
        "\n",
        "EMAIL = \"\"\"HI there, \\n\n",
        "I am emailing to say that I had a wonderful stay at your resort last week. \\n\n",
        "\n",
        "I really appreaciate what your staff did\n",
        "\n",
        "Thanks,\n",
        "Paul\n",
        "\"\"\"\n",
        "\n",
        "EMAIL = \"\"\"HI there, \\n\n",
        "I am emailing to say that the resort weather was way to cloudy and overcast. \\n\n",
        "I wanted to write a song called 'Here comes the sun but it never came'\n",
        "\n",
        "What should be the weather in Arizona in April?\n",
        "\n",
        "I really hope you fix this next time.\n",
        "\n",
        "Thanks,\n",
        "George\n",
        "\"\"\"\n",
        "\n",
        "EMAIL = \"\"\"HI there, \\n\n",
        "Why can't I get to sing?\n",
        "\n",
        "Thanks,\n",
        "Ringo\n",
        "\"\"\""
      ],
      "metadata": {
        "id": "YrQ-4T5NrlTS"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "##\n",
        "agents = EmailAgents()\n",
        "tasks = EmailTasks()\n",
        "\n",
        "## Agents\n",
        "categorizer_agent = agents.make_categorizer_agent()\n",
        "researcher_agent = agents.make_researcher_agent()\n",
        "email_writer_agent = agents.make_email_writer_agent()\n",
        "\n",
        "## Tasks\n",
        "categorize_email = tasks.categorize_email(EMAIL)\n",
        "research_info_for_email = tasks.research_info_for_email(EMAIL)\n",
        "draft_email = tasks.draft_email(EMAIL)\n"
      ],
      "metadata": {
        "id": "AQdhwjIrqebG"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "source": [
        "## Crew"
      ],
      "metadata": {
        "id": "Xma0GE-Kk9Ef"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "from crewai import Crew, Process\n",
        "\n",
        "# Instantiate your crew with a sequential process\n",
        "crew = Crew(\n",
        "    agents=[categorizer_agent, researcher_agent, email_writer_agent],\n",
        "    tasks=[categorize_email, research_info_for_email, draft_email],\n",
        "    verbose=2,\n",
        "    process=Process.sequential,\n",
        "    full_output=True,\n",
        "    share_crew=False,\n",
        "    step_callback=lambda x: print_agent_output(x,\"MasterCrew Agent\")\n",
        ")"
      ],
      "metadata": {
        "id": "e3SXzkhhn49N",
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "outputId": "10747d84-abd6-487f-8ff7-ae6fb685165d"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stderr",
          "text": [
            "WARNING:opentelemetry.trace:Overriding of current TracerProvider is not allowed\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "# Kick off the crew's work\n",
        "results = crew.kickoff()\n",
        "\n",
        "\n",
        "# Print the results\n",
        "print(\"Crew Work Results:\")\n",
        "print(results)\n",
        "\n",
        "# print(f\"Categorize Email: {categorize_email.output}\")\n",
        "print(crew.usage_metrics)"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "HexYqBNBdQ5B",
        "outputId": "894f2339-9b78-48ab-ce74-e6f151d8aebc"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "\u001b[1m\u001b[95m [DEBUG]: == Working Agent: Email Categorizer Agent\u001b[00m\n",
            "\u001b[1m\u001b[95m [INFO]: == Starting Task: Conduct a comprehensive analysis of the email provided and categorize into             one of the following categories:\n",
            "            price_equiry - used when someone is asking for information about pricing             customer_complaint - used when someone is complaining about something             product_enquiry - used when someone is asking for information about a product feature, benefit or service but not about pricing \\\n",
            "            customer_feedback - used when someone is giving feedback about a product             off_topic when it doesnt relate to any other category \n",
            "            EMAIL CONTENT:\n",
            "\n",
            " HI there, \n",
            "\n",
            "Why can't I get to sing?\n",
            "\n",
            "Thanks,\n",
            "Ringo\n",
            " \n",
            "\n",
            "\n",
            "            Output a single cetgory only\u001b[00m\n",
            "\n",
            "\n",
            "\u001b[1m> Entering new CrewAgentExecutor chain...\u001b[0m\n",
            "\u001b[32;1m\u001b[1;3mThought: After carefully analyzing the email content, I understand that the sender, Ringo, is expressing frustration about not being able to sing, but it's unclear what this has to do with our company or products. \n",
            "\n",
            "Final Answer: off_topic\u001b[0m\n",
            "\n",
            "\u001b[1m> Finished chain.\u001b[0m\n",
            "\u001b[1m\u001b[92m [DEBUG]: == [Email Categorizer Agent] Task output: off_topic\n",
            "\n",
            "\u001b[00m\n",
            "\u001b[1m\u001b[95m [DEBUG]: == Working Agent: Info Researcher Agent\u001b[00m\n",
            "\u001b[1m\u001b[95m [INFO]: == Starting Task: Conduct a comprehensive analysis of the email provided and the category             provided and search the web to find info needed to respond to the email\n",
            "\n",
            "            EMAIL CONTENT:\n",
            "\n",
            " HI there, \n",
            "\n",
            "Why can't I get to sing?\n",
            "\n",
            "Thanks,\n",
            "Ringo\n",
            " \n",
            "\n",
            "\n",
            "            Only provide the info needed DONT try to write the email\u001b[00m\n",
            "\n",
            "\n",
            "\u001b[1m> Entering new CrewAgentExecutor chain...\u001b[0m\n",
            "\u001b[32;1m\u001b[1;3mThought: The customer, Ringo, is writing about not being able to sing, but it's categorized as \"off_topic\". I need to investigate if there's any relevant information that can help the email writer respond to Ringo's concern.\n",
            "\n",
            "Action: duckduckgo_search\n",
            "Action Input: {\"q\": \"can't sing reasons\"}\u001b[0m\u001b[91m \n",
            "\n",
            "I encountered an error while trying to use the tool. This was the error: DuckDuckGoSearchRun._run() got an unexpected keyword argument 'q'.\n",
            " Tool duckduckgo_search accepts these inputs: A wrapper around DuckDuckGo Search. Useful for when you need to answer questions about current events. Input should be a search query.\n",
            "\u001b[00m\n",
            "\u001b[32;1m\u001b[1;3mThought: I need to find out why Ringo can't sing.\n",
            "\n",
            "Action: duckduckgo_search\n",
            "Action Input: \"reasons why people can't sing\"\u001b[0m\u001b[32;1m\u001b[1;3mThought: I still need to find out why Ringo can't sing.\n",
            "\n",
            "Action: duckduckgo_search\n",
            "Action Input: {\"search_query\": \"reasons why people can't sing\"}\u001b[0m\u001b[91m \n",
            "\n",
            "I encountered an error while trying to use the tool. This was the error: DuckDuckGoSearchRun._run() got an unexpected keyword argument 'search_query'.\n",
            " Tool duckduckgo_search accepts these inputs: A wrapper around DuckDuckGo Search. Useful for when you need to answer questions about current events. Input should be a search query.\n",
            "\u001b[00m\n",
            "\u001b[32;1m\u001b[1;3mThought: I've tried to use the tool, but it didn't work out. Now, I need to provide the best possible answer based on my understanding.\n",
            "\n",
            "Final Answer: NO USEFUL RESEARCH FOUND\u001b[0m\n",
            "\n",
            "\u001b[1m> Finished chain.\u001b[0m\n",
            "\u001b[1m\u001b[92m [DEBUG]: == [Info Researcher Agent] Task output: NO USEFUL RESEARCH FOUND\n",
            "\n",
            "\u001b[00m\n",
            "\u001b[1m\u001b[95m [DEBUG]: == Working Agent: Email Writer Agent\u001b[00m\n",
            "\u001b[1m\u001b[95m [INFO]: == Starting Task: Conduct a comprehensive analysis of the email provided, the category provided            and the info provided from the research specialist to write an email. \n",
            "            Write a simple, polite and too the point email which will respond to the customer's email.             If useful use the info provided from the research specialist in the email. \n",
            "            If no useful info was provided from the research specialist the answer politely but don't make up info.             \n",
            "            EMAIL CONTENT:\n",
            "\n",
            " HI there, \n",
            "\n",
            "Why can't I get to sing?\n",
            "\n",
            "Thanks,\n",
            "Ringo\n",
            " \n",
            "\n",
            "\n",
            "            Output a single cetgory only\u001b[00m\n",
            "\n",
            "\n",
            "\u001b[1m> Entering new CrewAgentExecutor chain...\u001b[0m\n",
            "\u001b[32;1m\u001b[1;3mThought: I need to ask Ringo more questions to clarify what he means by \"Why can't I get to sing?\" as the email is categorized as off_topic and there is no useful research found.\n",
            "\n",
            "Final Answer:\n",
            "\n",
            "Dear Ringo,\n",
            "\n",
            "Thank you for reaching out to us. I'm happy to help you with your concern. However, I'm not entirely sure what you mean by \"Why can't I get to sing?\" Could you please provide more context or clarify what you're trying to accomplish or what issue you're facing?\n",
            "\n",
            "Your help in providing more information will enable me to better understand your concern and provide a more accurate response.\n",
            "\n",
            "Looking forward to hearing back from you.\n",
            "\n",
            "Best regards,\n",
            "Sarah the Resident Manager\u001b[0m\n",
            "\n",
            "\u001b[1m> Finished chain.\u001b[0m\n",
            "\u001b[1m\u001b[92m [DEBUG]: == [Email Writer Agent] Task output: Dear Ringo,\n",
            "\n",
            "Thank you for reaching out to us. I'm happy to help you with your concern. However, I'm not entirely sure what you mean by \"Why can't I get to sing?\" Could you please provide more context or clarify what you're trying to accomplish or what issue you're facing?\n",
            "\n",
            "Your help in providing more information will enable me to better understand your concern and provide a more accurate response.\n",
            "\n",
            "Looking forward to hearing back from you.\n",
            "\n",
            "Best regards,\n",
            "Sarah the Resident Manager\n",
            "\n",
            "\u001b[00m\n",
            "Crew Work Results:\n",
            "{'final_output': 'Dear Ringo,\\n\\nThank you for reaching out to us. I\\'m happy to help you with your concern. However, I\\'m not entirely sure what you mean by \"Why can\\'t I get to sing?\" Could you please provide more context or clarify what you\\'re trying to accomplish or what issue you\\'re facing?\\n\\nYour help in providing more information will enable me to better understand your concern and provide a more accurate response.\\n\\nLooking forward to hearing back from you.\\n\\nBest regards,\\nSarah the Resident Manager', 'tasks_outputs': [TaskOutput(description=\"Conduct a comprehensive analysis of the email provided and categorize into             one of the following categories:\\n            price_equiry - used when someone is asking for information about pricing             customer_complaint - used when someone is complaining about something             product_enquiry - used when someone is asking for information about a product feature, benefit or service but not about pricing \\\\\\n            customer_feedback - used when someone is giving feedback about a product             off_topic when it doesnt relate to any other category \\n            EMAIL CONTENT:\\n\\n HI there, \\n\\nWhy can't I get to sing?\\n\\nThanks,\\nRingo\\n \\n\\n\\n            Output a single cetgory only\", summary='Conduct a comprehensive analysis of the email provided and categorize...', exported_output='off_topic', raw_output='off_topic'), TaskOutput(description=\"Conduct a comprehensive analysis of the email provided and the category             provided and search the web to find info needed to respond to the email\\n\\n            EMAIL CONTENT:\\n\\n HI there, \\n\\nWhy can't I get to sing?\\n\\nThanks,\\nRingo\\n \\n\\n\\n            Only provide the info needed DONT try to write the email\", summary='Conduct a comprehensive analysis of the email provided and the...', exported_output='NO USEFUL RESEARCH FOUND', raw_output='NO USEFUL RESEARCH FOUND'), TaskOutput(description=\"Conduct a comprehensive analysis of the email provided, the category provided            and the info provided from the research specialist to write an email. \\n            Write a simple, polite and too the point email which will respond to the customer's email.             If useful use the info provided from the research specialist in the email. \\n            If no useful info was provided from the research specialist the answer politely but don't make up info.             \\n            EMAIL CONTENT:\\n\\n HI there, \\n\\nWhy can't I get to sing?\\n\\nThanks,\\nRingo\\n \\n\\n\\n            Output a single cetgory only\", summary='Conduct a comprehensive analysis of the email provided, the category...', exported_output='Dear Ringo,\\n\\nThank you for reaching out to us. I\\'m happy to help you with your concern. However, I\\'m not entirely sure what you mean by \"Why can\\'t I get to sing?\" Could you please provide more context or clarify what you\\'re trying to accomplish or what issue you\\'re facing?\\n\\nYour help in providing more information will enable me to better understand your concern and provide a more accurate response.\\n\\nLooking forward to hearing back from you.\\n\\nBest regards,\\nSarah the Resident Manager', raw_output='Dear Ringo,\\n\\nThank you for reaching out to us. I\\'m happy to help you with your concern. However, I\\'m not entirely sure what you mean by \"Why can\\'t I get to sing?\" Could you please provide more context or clarify what you\\'re trying to accomplish or what issue you\\'re facing?\\n\\nYour help in providing more information will enable me to better understand your concern and provide a more accurate response.\\n\\nLooking forward to hearing back from you.\\n\\nBest regards,\\nSarah the Resident Manager')]}\n",
            "{'total_tokens': 39762, 'prompt_tokens': 36306, 'completion_tokens': 3456, 'successful_requests': 54}\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "!cat /content/draft_email.txt"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "cP7KiMdkbIAh",
        "outputId": "503aa595-a619-46ae-e7b4-48e466f7cb6d"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Dear Ringo,\n",
            "\n",
            "Thank you for reaching out to us. I'm happy to help you with your concern. However, I'm not entirely sure what you mean by \"Why can't I get to sing?\" Could you please provide more context or clarify what you're trying to accomplish or what issue you're facing?\n",
            "\n",
            "Your help in providing more information will enable me to better understand your concern and provide a more accurate response.\n",
            "\n",
            "Looking forward to hearing back from you.\n",
            "\n",
            "Best regards,\n",
            "Sarah the Resident Manager"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "!cat /content/email_category.txt"
      ],
      "metadata": {
        "id": "uNbw6y96bICK",
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "outputId": "cd738712-549b-436b-a1b6-2394759d24fd"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "off_topic"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "!cat /content/research_info.txt"
      ],
      "metadata": {
        "id": "MNx8mRoGbIES",
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "outputId": "66cb0ea6-2827-4376-bd3f-67e7b4b8d85c"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "NO USEFUL RESEARCH FOUND"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [],
      "metadata": {
        "id": "FWAlIQp9bIGC"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [],
      "metadata": {
        "id": "DQMiUwjSbIIk"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [],
      "metadata": {
        "id": "1452sfq-bIMu"
      },
      "execution_count": null,
      "outputs": []
    }
  ]
}